#include "ActionApiCancleBet.h"
#include "json.h"
#include "util.h"
#include "streamdata.h"
#include "agency_service.h"
#include "account_service.h"
#include "agencymgr.h"
#include "api_order_service.h"
#include "flow_service.h"



static std::map<std::string,std::string> http_json_heads = {{"Content-Type","application/json"}};

static bool __init__ = ActionApiCancleBet::Init();

bool ActionApiCancleBet::Init()
{
    Ctx.msg_router.BindMsg(agency_api::AGENCY_API_MSGID_CANCLE_BET_REQ, ActionApiCancleBet::HandleCancle);

    AgencyService::Instance()->ListenOnAgencyGet(AgencyService::CANCLE_BET, ActionApiCancleBet::OnAgencyGet);

    return true;
}

void ActionApiCancleBet::HandleCancle(MsgData&& msg_data)
{
    agency_api::CancelBetReq req;
    agency_api::CancelBetResp resp;

    do {
        if (!req.ParseFromArray(msg_data.data.data(), msg_data.data.size()))
        {
            resp.set_errorcode(agency_api::ErrorCode::DataParseErr);
            log_error("parser msg failed");
            break;
        }

        if (req.bet() < 0) req.set_bet(-req.bet());
        if (req.preserve() < 0) req.set_preserve(-req.preserve());

        log_debug("req:%s", req.ShortDebugString().c_str());

        stAgency* agency = AgencyMgr::Instance()->Get(req.user_basic().agency());
        if (agency != nullptr)
        {
            Request(agency->call_url, req.trans(), req.uid(), msg_data.svtype, msg_data.svid, msg_data.uuid, req.scene_from(), 
                req.order_id(), req.cycle(), req.bet(), req.preserve(), 
                req.user_basic().agency(), req.user_basic().token(), agency->currency, agency->currency_unit_multi, req.user_basic().username(), req.user_basic().platform()
                , agency->id, req.game(), req.user_basic().balance());
        }
        else
        {
            StreamData stream_data;
            StreamDataWriter writer(stream_data);
            writer.WriteShort(msg_data.svtype);
            writer.WriteInt(msg_data.svid);
            writer.WriteInt(msg_data.uuid);
            writer.WriteInt(req.scene_from());
            writer.WriteInt(req.uid());
            writer.WriteInt(req.game());
            writer.WriteInt64(req.cycle());
            writer.WriteInt64(req.order_id());
            writer.WriteInt64(req.bet());
            writer.WriteInt64(req.preserve());
            writer.WriteString(req.trans());
            writer.WriteString(req.user_basic().agency());
            writer.WriteString(req.user_basic().token());
            writer.WriteString(req.user_basic().username());
            writer.WriteString(req.user_basic().platform());
            writer.WriteInt64(req.user_basic().balance());

            if (!AgencyService::Instance()->HandleGetAgency(req.user_basic().agency(), std::move(stream_data.Data()), AgencyService::CANCLE_BET))
            {
                resp.set_errorcode(agency_api::ErrorCode::AgentGetErr);
                log_error("parser msg failed");
                break;
            }
        }

        return;
    } while(false);

    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_uid(req.uid());
        resp.set_trans(req.trans());
        resp.set_message(ToString(resp.errorcode()));
        Ctx.host->MtSendtoOneSrv(agency_api::AGENCY_API_MSGID_CANCLE_BET_RESP, &resp, msg_data.svtype, msg_data.svid, false, msg_data.uuid);
    }
}

void ActionApiCancleBet::OnAgencyGet(std::int32_t err_code, stAgency* agency, std::string&& trans)
{
    StreamData stream_data(std::move(trans));
    StreamDataReader reader(stream_data);
    std::uint16_t svtype = reader.ReadShort();
    std::uint32_t svid = reader.ReadInt();
    std::uint32_t uuid = reader.ReadInt();
    std::uint32_t scene_from = reader.ReadInt();
    std::uint32_t uid = reader.ReadInt();
    std::uint32_t game = reader.ReadInt();
    std::uint64_t cycle = reader.ReadInt64();
    std::uint64_t order_id = reader.ReadInt64();
    std::int64_t bet = reader.ReadInt64();
    std::int64_t preserve = reader.ReadInt64();
    trans = reader.ReadString();
    std::string agency_name = reader.ReadString();
    std::string token = reader.ReadString();
    std::string username = reader.ReadString();
    std::string platform = reader.ReadString();
    std::int64_t balance = reader.ReadInt64();

    agency_api::CancelBetResp resp;
    do
    {
        if (err_code != 0)
        {
            resp.set_errorcode(agency_api::ErrorCode::AgencyGetErr);
            log_error("get account info failed,uid:%u,err_code:%d", uid, err_code);
            break;
        }
        if (agency == nullptr)
        {
            resp.set_errorcode(agency_api::ErrorCode::AgencyGetErr);
            log_error("account is nullptr,uid:%u,err_code:%d", uid, err_code);
            break;
        }
		log_debug("agency:%s", agency->ToString().c_str());
    
        Request(agency->call_url, trans, uid, svtype, svid, uuid, scene_from,
            order_id, cycle, bet, preserve, 
            agency_name, token, agency->currency, agency->currency_unit_multi, username, platform,
            agency->id, game, balance);

        return;
    } while(false);

    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_uid(uid);
        resp.set_trans(std::move(trans));
        resp.set_message(ToString(resp.errorcode()));
        Ctx.host->MtSendtoOneSrv(agency_api::AGENCY_API_MSGID_CANCLE_BET_RESP, &resp, svtype, svid, false, uuid);
    }
}


void ActionApiCancleBet::Request(const std::string& baseurl, const std::string& trans
        ,std::uint32_t uid, std::uint16_t svtype, std::uint32_t svid, std::uint32_t uuid, std::uint32_t scene_from,
        std::uint64_t order_id, std::uint64_t cycle, std::int64_t bet, std::int64_t preserve, 
        const std::string& agency, const std::string& token, const std::string& currency, std::int64_t currency_unit_multi, const std::string& username, const std::string& platform
        , std::uint32_t agency_id, std::uint32_t gameid, std::int64_t balance)
{
    agency_api::CancelBetResp resp;
    do
    {
        std::string req_id = GenTransId();
        std::uint64_t now = CTools::GetUnixTime();

        if (currency_unit_multi == 0)
        {
            resp.set_errorcode(agency_api::ErrorCode::AbnormalErr);
            log_error("currency_unit_multi is 0, uid:%u ,cycle:%lld,order_id:%lld,currency:%s", uid, cycle, order_id, currency.c_str());
            break;
        }

        Json::Value http_req;
        http_req["reqId"] = req_id;
        http_req["currency"] = currency;
        http_req["game"] = gameid;
        http_req["round"] = Json::Int64(order_id);
        http_req["betAmount"] = bet * 1.0 / currency_unit_multi;
        http_req["winloseAmount"] = 0;
        http_req["userId"] = username;
        http_req["token"] = token;
        http_req["sessionId"] = Json::Int64(cycle);
        http_req["type"] = 1;  // 1：下注,2结算
        http_req["preserve"] = preserve * 1.0 / currency_unit_multi;

        std::string json_string = CTools::ToStr(http_req);
        std::string url = baseurl + "/cancelSessionBet";
        
        api_order::ApiOrder api_order;
        api_order.set_scene_from(scene_from);
        api_order.set_stype_from(svtype);
        api_order.set_svid_from(svid);
        api_order.set_uid(uid);
        api_order.set_username(username);
        api_order.set_agency(agency);
        api_order.set_token(token);
        api_order.set_platform(platform);
        api_order.set_currency(currency);
        api_order.set_gameid(gameid);
        api_order.set_op(api_order::API_ORDER_OP_CANCLE_BET);
        api_order.set_url(url);
        api_order.set_req_id(req_id);
        api_order.set_req_body(json_string);
        api_order.set_start_time(now);
        api_order.set_update_time(now);
        api_order.set_cycle(cycle);
        api_order.set_orderid(order_id);
        api_order.set_bet(bet);
        api_order.set_preserve(preserve);
        api_order.set_balance(balance);

        std::uint32_t event_id = 0;
        // 请求http网络
        if (!Ctx.msg_router.sendHttpPOST(url, json_string, http_json_heads, event_id) || (event_id == 0))
        {
            resp.set_errorcode(agency_api::ErrorCode::SendPostErr);
            log_error("net post failed,url:%s,param:%s", url.c_str(),json_string.c_str());
            break;
        }
        log_debug("http post,url:%s,param:%s", url.c_str(), json_string.c_str());
        // 添加回调监听
        Ctx.msg_router.AddCurlEvent(event_id, [uid, svtype, svid, uuid, currency_unit_multi, trans=std::move(trans),agency_id,gameid,cycle,order_id,balance,bet,preserve,
            url=std::move(url), json_string= std::move(json_string), api_order_v = std::move(api_order)](std::string& body, bool is_ok){
            agency_api::CancelBetResp resp;
            Json::Value http_resp;
            
            std::uint64_t now = CTools::GetUnixTime();

            api_order::ApiOrder api_order = std::move(api_order_v);
            api_order.set_update_time(now);
            api_order.set_resp_body(body);
            do
            {
                // 网络错误
                if (!is_ok)
                {
                    resp.set_errorcode(agency_api::ErrorCode::RespTimeout);
                    log_error("time out,url:%s,param:%s", url.c_str(), json_string.c_str());
                    break;
                }
                
                // 解析返回格式
                if (!CTools::FromStr(http_resp, body))
                {
                    // resp.set_errorcode(agency_api::ErrorCode::DataParseErr);
                    resp.set_errorcode(agency_api::ErrorCode::RespTimeout);
                    log_error("resp from json failed, body:%s ,url:%s,param:%s", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }

                if (!http_resp.isMember("username") || !http_resp["username"].isString()
                    || !http_resp.isMember("currency") || !http_resp["currency"].isString()
                    || !http_resp.isMember("balance") || !http_resp["balance"].isDouble()
                    || !http_resp.isMember("errorCode") || !http_resp["errorCode"].isInt()
                    )
                {
                    resp.set_errorcode(agency_api::ErrorCode::InvalidParameter);
                    log_error("response param invalid, body:%s ,url:%s,param:%s", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }
            
                if (currency_unit_multi == 0)
                {
                    resp.set_errorcode(agency_api::ErrorCode::AbnormalErr);
                    log_error("currency_unit_multi is 0, body:%s ,url:%s,param:%s", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }

                resp.set_errorcode(http_resp["errorCode"].asInt());
                std::string username = http_resp["username"].asString();
                resp.set_balance(http_resp["balance"].asDouble() * currency_unit_multi);
                std::int64_t txid = 0;
                if (http_resp.isMember("txId")  && http_resp["txId"].isInt64()) 
                {
                    txid = http_resp["txId"].asInt64();
                }

                api_order.set_resp_id(txid);
                api_order.set_balance(resp.balance());
            } while (false);
            
            // 回包
            resp.set_uid(uid);
            resp.set_trans(std::move(trans));
            resp.set_message(ToString(resp.errorcode()));
            
            log_debug("resp:%s", resp.ShortDebugString().c_str());

            Ctx.host->MtSendtoOneSrv(agency_api::AGENCY_API_MSGID_CANCLE_BET_RESP, &resp, svtype, svid, false, uuid);
            
            // 上报流水
            if (api_order.scene_from() == 0)
            {
                FlowService::Instance()->OnCancleBet(resp.errorcode(), uid, GameProvider(), agency_id, gameid,cycle, order_id, api_order.start_time(),balance, bet, preserve, order_id);
            }

            // 订单更新
            api_order.set_err_code(resp.errorcode());
            ApiOrderService::Instance()->OnApiOrderUpdate(api_order);
        });

        return;
    } while(false);

    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_uid(uid);
        resp.set_trans(std::move(trans));
        resp.set_message(ToString(resp.errorcode()));
        Ctx.host->MtSendtoOneSrv(agency_api::AGENCY_API_MSGID_CANCLE_BET_RESP, &resp, svtype, svid, false, uuid);
    }
}













